home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / HDX_BACK / HDX302.ST / SCSI.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  17.8 KB  |  672 lines

  1. ;+
  2. ; Edit History
  3. ;
  4. ; May-17-89    ml.    Started this with jwt's SCSI code.
  5. ; Aug-21-89    ml.    Added format code.
  6. ; Nov-17-89    ml.    Only add 8 to byte count on DMA reads, not writes.
  7. ; Dec-04-89    ml.    Always hand-shake last 8 bytes of data when writing
  8. ;            to disk because of hardware counter handling.
  9. ;            Added w4cntout().
  10. ;            (refer to comments at _wrtscsi())
  11. ; Jan-23-90    ml.    Undid modifications done on Dec-04-89.
  12. ;            (refer to comments at _wrtscsi())
  13. ;-
  14.  
  15.  
  16. .include    "defs.h"
  17. .include    "sysvar.h"
  18.  
  19.  
  20. ; Definitions
  21. REGBASE    equ    1    ; most are on odd part of data bus
  22. REGSTEP    equ    2    ; most registers are on word boundaries
  23.  
  24. ; 68901 MFP definitions
  25.  
  26. MFP    equ    $FFFFFA01
  27.  
  28. ;GPIP    equ    MFP+$00
  29. AER    equ    MFP+$02
  30. DDR    equ    MFP+$04
  31. IERA    equ    MFP+$06
  32. ERB    equ    MFP+$08
  33. IPRA    equ    MFP+$0A
  34. IPRB    equ    MFP+$0C
  35. ISRA    equ    MFP+$0E
  36. ISRB    equ    MFP+$10
  37. IMRA    equ    MFP+$12
  38. IMRB    equ    MFP+$14
  39. VR    equ    MFP+$16
  40. TACR    equ    MFP+$18
  41. TBCR    equ    MFP+$1A
  42. TCDCR    equ    MFP+$1C
  43. TADR    equ    MFP+$1E
  44. TBDR    equ    MFP+$20
  45. TCDR    equ    MFP+$22
  46. TDDR    equ    MFP+$24
  47. SCR    equ    MFP+$26
  48. UCR    equ    MFP+$28
  49. RSR    equ    MFP+$2A
  50. TSR    equ    MFP+$2C
  51. UDR    equ    MFP+$2E
  52.  
  53. MFP2    equ    $FFFFFA81
  54. GPIP2    equ    MFP2+$00
  55. AER2    equ    MFP2+$02
  56. DDR2    equ    MFP2+$04
  57. IERA2    equ    MFP2+$06
  58. IERB2    equ    MFP2+$08
  59. IPRA2    equ    MFP2+$0A
  60. IPRB2    equ    MFP2+$0C
  61. ISRA2    equ    MFP2+$0E
  62. ISRB2    equ    MFP2+$10
  63. IMRA2    equ    MFP2+$12
  64. IMRB2    equ    MFP2+$14
  65. VR2    equ    MFP2+$16
  66. TACR2    equ    MFP2+$18
  67. TBCR2    equ    MFP2+$1A
  68. TCDCR2    equ    MFP2+$1C
  69. TADR2    equ    MFP2+$1E
  70. TBDR2    equ    MFP2+$20
  71. TCDR2    equ    MFP2+$22
  72. TDDR2    equ    MFP2+$24
  73. SCR2    equ    MFP2+$26
  74. UCR2    equ    MFP2+$28
  75. RSR2    equ    MFP2+$2A
  76. TSR2    equ    MFP2+$2C
  77. UDR2    equ    MFP2+$2E
  78.     
  79. ; GPIP2 BIT ASSIGNMENTS
  80. GPIP2SCSI    equ    7    ; SCSI xIRQ
  81. GPIP2RTC    equ    6    ; RTC IRQ
  82. GPIP25        equ    5    ; 
  83. GPIP2CHGL    equ    4    ; ChangeLine
  84. GPIP2RI        equ    3    ; Ring Indicator (SCC Port B)
  85. GPIP2DBE    equ    2    ; DMA Bus Error
  86. LED1        equ    1    ; debug LED
  87. LED0        equ    0    ; debug LED
  88.  
  89. ; SCSI Interface (NCR 5380) for READ operations
  90. bSCSI    equ    $FFFF8780+REGBASE
  91. SCSIDB    equ    bSCSI+($00*REGSTEP)    ; current SCSI data bus
  92. SCSIICR    equ    bSCSI+($01*REGSTEP)    ; initiator command register
  93. SCSIMR    equ    bSCSI+($02*REGSTEP)    ; mode register
  94. SCSITCR    equ    bSCSI+($03*REGSTEP)    ; target command register
  95. SCSICR    equ    bSCSI+($04*REGSTEP)    ; current SCSI control register
  96. SCSIDSR    equ    bSCSI+($05*REGSTEP)    ; DMA status register
  97. SCSIIDR    equ    bSCSI+($06*REGSTEP)    ; input data register
  98. SCSIREI    equ    bSCSI+($07*REGSTEP)    ; reset error / interrupt
  99.  
  100. ; SCSI Interface (NCR 5380) for WRITE operations
  101. SCSIODR    equ    bSCSI+($00*REGSTEP)    ; output data register
  102. ;SCSIICR    bSCSI+($01*REGSTEP)    ; initiator command register
  103. ;SCSIMR        bSCSI+($02*REGSTEP)    ; mode register
  104. ;SCSITCR    bSCSI+($03*REGSTEP)    ; target command register
  105. SCSIISR    equ    bSCSI+($04*REGSTEP)    ; ID select register
  106. SCSIDS    equ    bSCSI+($05*REGSTEP)    ; start DMA send
  107. SCSIDTR    equ    bSCSI+($06*REGSTEP)    ; start DMS target receive
  108. SCSIDIR    equ    bSCSI+($07*REGSTEP)    ; start DMA initiator receive
  109.  
  110. ; SCSI DMA Controller
  111. bSDMAPTR    equ    $FFFF8701
  112. bSDMACNT    equ    $FFFF8709
  113. SDMARES        equ    $FFFF8710
  114. SDMACTL        equ    $FFFF8714    ; WORD
  115.  
  116. DMAOUT    equ    01
  117. DMAIN    equ    00
  118. DMAENA    equ    02
  119. DMADIS    equ    00
  120.  
  121. SCSIID    equ    6        ; our (host) SCSI ID
  122.  
  123. ;+
  124. ; Command length
  125. ;-
  126. NCMD    equ    6        ; length of short command (in bytes)
  127.  
  128.  
  129. .if    !DRIVER            ; not to be included in driver
  130. scxltmout:    dc.l    12001    ; SCSI extra long-timeout (>= 1 min)
  131. slwsclto:    dc.l    5000    ; SCSI long-timeout (25 S) for stunit()
  132. slwscsto:    dc.l    42    ; SCSI short-timeout (205 mS) for stunit()
  133. scltmout:    dc.l    401    ; SCSI long-timeout (at least 1000 ms)
  134. ;scltmout:    dc.l    201    ; SCSI long-timeout (at least 1000 ms)
  135. scstmout:    dc.l    201    ; SCSI short-timeout (at least 500 ms)
  136. ;scstmout:    dc.l    101    ; SCSI short-timeout (at least 500 ms)
  137. .even
  138. .endif    ;!DRIVER
  139.  
  140.  
  141. ;+
  142. ; smplscsi() - send a simple SCSI command (ie. no DMA involved)
  143. ;
  144. ;    d0.w = physical unit number
  145. ;    d1.l = transfer length (in bytes)
  146. ;    d2.w = command length (NCMD or LCMD)
  147. ;    a0.l = buffer address
  148. ;-
  149.     .globl    _smplscsi
  150. _smplscsi:
  151.     andi.w    #7,d0            ; mask off the flags to get unit num
  152.     bsr    sblkscsi        ; send command block
  153.     bpl.s    .0            ; if successful, wait for status
  154.     rts                ; else return
  155. .0:    bra    w4stat            ; waiting for status byte
  156.  
  157.  
  158. ;+
  159. ; rcvscsi() - send a SCSI command which receives data back.
  160. ;
  161. ; Passed:
  162. ;    d0.w = physical unit number
  163. ;    d1.l = transfer length (in bytes)
  164. ;    d2.w = command length (NCMD or LCMD)
  165. ;    a0.l = buffer address
  166. ;
  167. ; Comments:
  168. ;    The code that checks whether there is data left in the residue
  169. ; register does not work for some transfers of less than 4 bytes to a
  170. ; non-longword aligned address.  
  171. ;-
  172.     .globl    _rcvscsi
  173. _rcvscsi:
  174. .if    !SCDMA                ; if not doing DMA
  175.     move.l    a0,-(sp)        ; save buffer address
  176. .endif    ;SCDMA
  177.     andi.w    #7,d0            ; mask off the flags to get unit num
  178.  
  179. .if    SCDMA                ; if doing DMA
  180.     addq.l    #8,d1            ; add 8 because of hardware bug
  181. .endif    ;SCDMA
  182.  
  183.     move.w    d2,-(sp)        ; save the command length
  184.     bsr    sblkscsi        ; send command block
  185.     move.w    (sp)+,d2        ; restore the command length
  186. .if    !SCDMA                ; if not doing DMA
  187.     move.l    (sp)+,a0        ; restore buffer address
  188. .endif    ;SCDMA
  189.     tst.w    d0            ; successful?
  190.     bmi.s    rsend            ; if not successful, return
  191.  
  192.     move.b    #0,SCSIICR        ; deassert the data bus
  193.     move.b    #1,SCSITCR        ; set data in phase
  194.     move.b    SCSIREI,d0        ; clear potential interrupt
  195.  
  196. .if    SCDMA
  197.                     ; Set up the DMAC for data transfer
  198.     move.b    #2,SCSIMR        ; enable DMA mode
  199.     move.b    #0,SCSIDIR        ; start the DMA receive
  200.     move.w    #DMAIN,SDMACTL        ; set the DMAC direction to IN
  201.     move.w    #DMAIN+DMAENA,SDMACTL    ; turn on DMAC
  202.  
  203.     bsr    setscstmout        ; set up a short timeout
  204.     cmpi.w    #NCMD,d2        ; is this a long command?
  205.     beq.s    .0            ; if not, just go on
  206.     bsr    setscxltmout        ; else, set up an extra long timeout
  207. .0:    bsr    w4int            ; wait for interrupts
  208.     tst.w    d0            ; successful?
  209.     bne.s    rsend            ; if error, returns
  210.     bsr    w4stat            ; wait for status byte
  211.     tst.w    d0            ; successful?
  212.     bne.s    rsend            ; if error, returns
  213.     move.l    d0,-(sp)        ; else save returned status
  214.  
  215.     move.b    bSDMAPTR+6,d0        ; see if this was an odd transfer
  216.     andi.w    #3,d0            ; (ie, not multiple of 4)
  217.     beq.s    .2            ; no, nice and even (and easy)
  218.  
  219.     movea.l    #bSDMAPTR,a1        ; a1 -> DMA address
  220.     movep.l    (0,a1),d0        ; d0 = current value of DMA pointer
  221.     move.l    d0,d1            ; d1 = current value of DMA pointer
  222.  
  223.     andi.w    #3,d0            ; # bytes left in residue register
  224.     andi.w    #$FFFF-3,d1        ; where does data go to?
  225.     movea.l    d1,a0            ; a0 -> where rest of data should go
  226.     move.l    SDMARES,d1        ; get the residue
  227.     subq.w    #1,d0            ; dbra likes one less than count
  228. .1:    rol.l    #8,d1            ; tranfer residue to buffer
  229.     move.b    d1,(a0)+
  230.     dbra    d0,.1
  231.  
  232. .2:    move.l    (sp)+,d0        ; recall the status byte
  233.  
  234. .else    ;SCDMA
  235.     movea.l    a0,a1            ; a1 -> buffer to read into
  236.     movea.l    #bSCSI,a2        ; a2 -> 5380
  237. .3:    bsr    setscstmout
  238.     bsr    w4req            ; wait for REQ to come
  239.     bmi.s    rsend            ; if timed out, returns
  240.     btst    #3,5*REGSTEP(a2)    ; still in data in phase?
  241.     beq    w4stat            ; no, go get status
  242.     move.b    (a2),(a1)+        ; read the data byte
  243.     bsr    doack
  244.     bra.s    .3            ; do next byte
  245. .endif    ;SCDMA
  246. rsend:    rts
  247.  
  248.  
  249. ;+
  250. ; wrtscsi() - send a SCSI command which will write data to the target
  251. ;
  252. ; Passed:
  253. ;    d0.w = physical unit number
  254. ;    d1.l = transfer length (in bytes)
  255. ;    d2.w = command length (NCMD or LCMD)
  256. ;    a0.l = buffer address
  257. ;
  258. ; Comments: 
  259. ; 12/04/89 ml
  260. ;    Bus error occurs when doing a write to the disk that ends at top
  261. ; of memory.  The DMA counter is decremented when the bytes are written 
  262. ; from the ping pong buffers to the device, not when bytes are grapped 
  263. ; from RAM to the ping pong buffers.  Well, AFTER the last 8 bytes are 
  264. ; read into the ping pong buffers and BEFORE they are written to the 
  265. ; device, the chip will attempt to read the NEXT 8 bytes into the ping 
  266. ; pong buffers which results in a bus error because it will be reading 
  267. ; pass top of memory.  To get around this HARDWARE BUG, the code will 
  268. ; ALWAYS handshake the last 8 bytes over instead of DMAing them.
  269. ;
  270. ; 01/23/90 ml
  271. ;    A. Pratt said he's willing to move the screen down and sacrifice
  272. ; 16 bytes of memory.  So, code added on 12/04/89 is commented out.
  273. ;-
  274.     .globl    _wrtscsi
  275. _wrtscsi:
  276.     andi.w    #7,d0            ; mask off the flags to get unit num
  277.  
  278. .if    !SCDMA
  279.     move.l    a0,-(sp)        ; save beginning buffer address
  280. .endif    ;!SCDMA
  281.  
  282. .0:    move.w    d2,-(sp)        ; save command length
  283.     bsr    sblkscsi        ; send command block
  284.     move.w    (sp)+,d2        ; restore command length
  285. .if    !SCDMA
  286.     move.l    (sp)+,a0        ; a0 = where DMA ends
  287. .endif    ;!SCDMA
  288.     tst.w    d0            ; successful?
  289.     bpl.s    .1            ; if successful, go on
  290.     rts                ; else return
  291.  
  292. .1:    move.b    #0,SCSITCR        ; set data out phase
  293.     move.b    SCSIREI,d0        ; clear potential interrupt
  294.  
  295. .if    SCDMA
  296.                     ; Set up the DMAC for data transfer
  297.     move.b    #2,SCSIMR        ; enable DMA mode
  298.     move.b    #0,SCSIDS        ; start the DMA send
  299.     move.w    #DMAOUT,SDMACTL        ; set the DMAC direction
  300.     move.w    #DMAOUT+DMAENA,SDMACTL    ; turn on DMAC
  301.  
  302.     bsr    setscstmout        ; set up a short timeout
  303.     cmpi.w    #NCMD,d2        ; is this a long command?
  304.     beq.s    .2            ; if not, just go on
  305.     bsr    setscxltmout        ; set up an extra long timeout
  306. .2:    bsr    w4int            ; wait for interrupts
  307.     tst.w    d0
  308.     bne.s    wsend            ; if failed, return
  309.     bsr    w4stat            ; wait for status byte
  310.  
  311. .else    ;SCDMA
  312.                     ; hand shake the rest over the bus
  313.     movea.l    a0,a1            ; a1 -> buffer to write from
  314.     movea.l    #bSCSI,a2        ; a2 -> 5380
  315. .3:    bsr    setscstmout
  316.     bsr    w4req            ; wait for REQ to come
  317.     bmi.s    wsend            ; if timed out, returns
  318.     btst    #3,5*REGSTEP(a2)    ; still in data out phase?
  319.     beq    w4stat            ; no, go get status
  320.     move.b    (a1)+,(a2)        ; write the data byte
  321.     bsr    doack
  322.     bra.s    .3            ; do next byte
  323. .endif    ;SCDMA
  324. wsend:    rts
  325.  
  326.  
  327.  
  328. ;+
  329. ; sblkscsi() - set DMA pointer and count and send command block
  330. ;
  331. ; Passed:
  332. ;    d0.w = physical unit number
  333. ;    d1.l = transfer length (in bytes)
  334. ;    d2.w = command length (NCMD or LCMD)
  335. ;    a0.l = buffer address
  336. ;
  337. ; Returns:
  338. ;    d0.l =  0 if successful
  339. ;    d0.l = -1 if timeout
  340. ;-
  341.     .extern    _cmdblk
  342. sblkscsi:
  343.     movem.l    d1-d2/a0,-(sp)        ; preserve d1, d2 and a0
  344.     move.w    d0,-(sp)        ; physical unit #
  345.     bsr    selscsi            ; select the unit
  346.     addq.l    #2,sp            ; clean up stack
  347.     movem.l    (sp)+,d1-d2/a0        ; restore d1, d2 and a0
  348.     tst.w    d0            ; selection successful?
  349.     bmi.s    sbsend            ; if timed out, return
  350.                     ; else proceed
  351. .if    SCDMA
  352.     move.l    a0,d0            ; d0 = buffer address
  353.     movea.l    #bSDMAPTR,a1        ; a1 -> DMA address
  354.     movep.l    d0,(0,a1)        ; set DMA pointer
  355.  
  356.     movea.l    #bSDMACNT,a1        ; a1 -> DMA count
  357.     movep.l    d1,(0,a1)        ; set DMA count
  358. .endif    ;SCDMA
  359.  
  360.     move.b    #2,SCSITCR        ; assert C/D
  361.     move.b    #1,SCSIICR        ; assert data bus
  362.  
  363.     bsr    setscstmout        ; set up timeout for sending cmdblk
  364.     lea    _cmdblk,a1        ; a1 -> command block
  365.     subq.w    #1,d2            ; dbra likes one less
  366. .0:    move.b    (a1)+,d0        ; d0.b = byte to be sent
  367.     bsr    hshake            ; write that byte
  368.     tst.w    d0
  369.     bmi.s    sbsend            ; if timed-out, returns
  370.     dbra    d2,.0            ; until whole command block is sent
  371.     moveq    #0,d0            ; all operations successful
  372. sbsend: rts                ; heading home
  373.  
  374.  
  375. ;+
  376. ; BOOLEAN selscsi(SCSIUnit) 
  377. ; WORD SCSIUnit;
  378. ;-
  379. selscsi:
  380.     bsr    setscstmout        ; set up a short timeout
  381. .0:    btst    #6,SCSICR        ; STILL busy from last time?
  382.     beq.s    .1            ; if not, it's available
  383.     cmp.l    (a0),d1            ; timeout?
  384.     bhi.s    .0            ; not yet, wait some more
  385.     bra.s    .3            ; else, return error
  386.  
  387. .1:    move.b    #0,SCSITCR        ; data out phase
  388.     move.b    #0,SCSIISR        ; no interrupt from selection
  389.     move.b    #$0c,SCSIICR        ; assert BSY and SEL
  390. ; set dest SCSI IDs
  391.     clr.w    d0
  392.     move.w    4(sp),d1        ; get the SCSI unit desired
  393.     bset    d1,d0            ; set the appropriate bit
  394.     move.b    d0,SCSIODR        ; (real code would set ours too)
  395.  
  396.     move.b    #$0d,SCSIICR        ; assert BUSY, SEL and data bus
  397.     andi.b    #$FE,SCSIMR        ; clear arbitrate bit
  398.     andi.b    #$F7,SCSIICR        ; clear BUSY
  399.     nop                ; 2 deskew delays
  400.     nop
  401.  
  402.     bsr    setscstmout        ; set up for timeout
  403. .2:    btst    #6,SCSICR        ; wait for bus to be busy
  404.     bne.s    .4
  405.     cmp.l    (a0),d1
  406.     bhi.s    .2
  407.  
  408. .3:    moveq    #-1,d0            ; time out
  409.     bra.s    .5
  410.     
  411. .4:    clr.w    d0            ; selection successful
  412. .5:    move.b    #$0,SCSIICR        ; clear SEL and data bus assertion
  413.     rts
  414.  
  415.  
  416. *+
  417. * VOID resetscsi();
  418. *-
  419.     .globl    resetscsi
  420. resetscsi:
  421.     move.b    #$80,SCSIICR    ; assert RST
  422.     bsr    setscstmout    ; wait (at least) 250 ms
  423. .0:    cmp.l    (a0),d1
  424.     bhi.s    .0
  425.     move.b    #$00,SCSIICR
  426.     bsr    setscltmout    ; wait (at least) 1000 ms
  427. .1:    cmp.l    (a0),d1
  428.     bhi.s    .1
  429.     rts
  430.  
  431.  
  432. ;+
  433. ; w4int - wait for interrupts from 5380 or DMAC during DMA tranfers
  434. ;      and get status and message byte (through w4stat()).
  435. ;
  436. ; Passed:
  437. ;    d1.l = expiration time
  438. ;    a0.l = address of _hz_200
  439. ;
  440. ; Returns:
  441. ;    d0.l = returned status or timeout error
  442. ;
  443. ; Comments:
  444. ;    When 5380 is interrupted, it indicates a change of data to
  445. ; status phase (i.e., DMA is done), or ...
  446. ;    When DMAC is interrupted, it indicates either DMA count is
  447. ; zero, or there is an internal bus error.
  448. ;-
  449. w4int:    
  450. .0:    btst    #GPIP2SCSI,GPIP2    ; wait for 5380 to interrupt
  451.     bne.s    .3            ; active HIGH
  452.  
  453.     btst    #5,GPIP2        ; or for DMAC to interrupt
  454.     beq.s    .1            ; active LOW
  455.     cmp.l    (a0),d1            ; time's up yet?
  456.     bhi.s    .0            ; if not, wait some more
  457.                     ; timed-out
  458.     bsr    resetscsi        ; reset the SCSI bus
  459.     moveq    #-1,d0            ; else, return timeout
  460.     bra.s    w4iend
  461.  
  462. .1:    move.w    SDMACTL,d0        ; get the DMAC status
  463.     andi.l    #$80,d0            ; check for bus err/ignore cntout ints
  464.     beq.s    .0            ; if fine, wait for interrupts again
  465.     move.w    d0,-(sp)        ; save the returned status
  466. .2:    bsr    resetscsi        ; reset the SCSI bus
  467.     move.w    (sp)+,d0        ; d0 = return code
  468.     bra.s    w4iend            ; returns
  469. .3:    moveq    #0,d0            ; DMA is successful
  470.     move.w    d0,-(sp)        ; save status
  471.     move.b    SCSIREI,d0        ; clear potential interrupt
  472.     move.w    #DMADIS,SDMACTL        ; disable DMA
  473.     move.b    #0,SCSIMR        ; disable DMA mode
  474.     move.b    #0,SCSIICR        ; make sure data bus is not asserted
  475.     move.w    (sp)+,d0        ; restore status
  476. w4iend:    rts
  477.  
  478.  
  479. ;+
  480. ; w4stat - wait for status byte and message byte.
  481. ;
  482. ; Returns:
  483. ;    d0.l = returned status or timeout error
  484. ;-
  485. w4stat:    bsr    setscstmout        ; set up time-out for REQ and ACK
  486.     move.b    #3,SCSITCR        ; status in phase
  487.     move.b    SCSIREI,d0        ; clear potential interrupt
  488.  
  489.     bsr    w4req            ; wait for status byte
  490.     bmi.s    w4send            ; if timed-out, returns
  491. gstat:    moveq    #0,d0            ; clear d0
  492.     move.b    SCSIDB,d0        ; get the status byte
  493.     move.l    d0,-(sp)        ; save the status byte
  494.     bsr    setscstmout        ; set up time-out for REQ and ACK
  495.     bsr    doack            ; signal that status byte is here
  496.     tst.w    d0            ; timed-out?
  497.     beq.s    .1            ; if not, wait for message byte
  498.  
  499. .0:    addq.l    #4,sp            ; else clean up stack
  500.     bra.s    w4send            ; and return
  501.  
  502. .1:    bsr    setscstmout        ; set up timeout for REQ and ACK
  503.     bsr    w4req            ; wait for message byte
  504.     bmi.s    .0            ; if timed-out, returns
  505.  
  506.     move.b    SCSIDB,d0        ; get and ignore message byte
  507.     bsr    doack            ; signal that message byte is here
  508.     tst.w    d0            ; timed-out?
  509.     bmi.s    .0            ; if so, return timeout
  510. ;
  511. ; For debugging SEA177N - add a delay after receiving message byte
  512. ;
  513.     move.l    #_hz_200,a0
  514.     move.l    #4,d1
  515.     add.l    (a0),d1
  516. .2:    cmp.l    (a0),d1
  517.     bhi.s    .2
  518. ;
  519.     move.l    (sp)+,d0        ; recall the status byte
  520. w4send:    rts
  521.  
  522.  
  523. ;+
  524. ; w4req() - wait for REQ to come
  525. ;
  526. ; Passed:
  527. ;    d1.l = expiration time
  528. ;    a0.l = address of _hz_200
  529. ;
  530. ; Returns:
  531. ;     0 - if successful
  532. ;    -1 - times out
  533. ;-
  534. w4req:
  535. .0:    btst    #5,SCSICR        ; waiting for REQ to come
  536.     bne.s    .1            ; if REQ comes, done
  537.     cmp.l    (a0),d1            ; time's up?
  538.     bhi.s    .0            ; if not, wait some more
  539.     moveq    #-1,d0            ; else, returns timed out
  540.     bra.s    w4rend
  541. .1:    moveq    #0,d0            ; returns successful
  542. w4rend:    rts
  543.  
  544.  
  545. ;+
  546. ; doack() - assert ACK
  547. ;
  548. ; Passed:
  549. ;    d1.l = expiration time
  550. ;    a0.l = address of _hz_200
  551. ;
  552. ; Returns:
  553. ;     0 - if successful
  554. ;    -1 - times out
  555. ;-
  556. doack:    ori.b    #$11,SCSIICR        ; assert ACK (and data bus)
  557. .0:    btst    #5,SCSICR        ; wait for REQ to go away
  558.     beq.s    .1            ; if REQ goes away, done
  559.     cmp.l    (a0),d1            ; time's up?
  560.     bhi.s    .0            ; if not, wait some more
  561.     moveq    #-1,d0            ; else returns timed out
  562.     bra.s    doaend
  563. .1:    moveq    #0,d0            ; returns successful
  564. doaend:    andi.b    #$ef,SCSIICR        ; clear ACK
  565.     rts
  566.  
  567.  
  568. ;+
  569. ; hshake() - hand shake a byte over to the controller
  570. ;
  571. ; Passed:
  572. ;    d0.b = byte to be handed over
  573. ;    d1.l = expiration time
  574. ;    a0.l = address of _hz_200
  575. ;
  576. ; Returns:
  577. ;    Whatever w4req() or doack() returns, which is:
  578. ;         0 - if successful
  579. ;        -1 - times out
  580. ;-
  581. hshake:    move.w    d0,-(sp)        ; preserve d0.w
  582.     bsr    w4req            ; wait for REQ to come
  583.     bmi.s    hsend            ; if timed out, returns
  584.     move.b    1(sp),SCSIDB        ; write a byte out to data bus
  585.     bsr    doack            ; assert ACK
  586. hsend:    addq.l    #2,sp            ; clean up stack
  587.     rts
  588.  
  589.  
  590. ;+
  591. ; setscstmout - set up a timeout count for the SCSI for SCSTMOUT long
  592. ;
  593. ; Returns:
  594. ;    a0.l = address of _hz_200 clock
  595. ;    d1.l = expiration time
  596. ;-
  597.  
  598. .if    DRIVER                ; to be included in driver
  599.     .extern    scstmout
  600. .endif    ;DRIVER
  601.  
  602. setscstmout:
  603.     movea.l    #_hz_200,a0        ; a0 -> 200 hz clock
  604.     move.l    scstmout,d1        ; d0 = scstmout _hz_200 clicks
  605.     add.l    (a0),d1            ; d0 = curr time + # clicks to wait
  606.     rts
  607.  
  608.  
  609. ;+
  610. ; setscltmout - set up a timeout count for the SCSI for SCLTMOUT long
  611. ;
  612. ; Returns:
  613. ;    a0.l = address of _hz_200 clock
  614. ;    d1.l = expiration time
  615. ;-
  616.  
  617. .if    DRIVER                ; to be included in driver
  618.     .extern    scltmout
  619. .endif    ;DRIVER
  620.  
  621. setscltmout:
  622.     movea.l    #_hz_200,a0        ; a0 -> 200 hz clock
  623.     move.l    scltmout,d1        ; d0 = scltmout _hz_200 clicks
  624.     add.l    (a0),d1            ; d0 = curr time + # clicks to wait
  625.     rts
  626.  
  627.  
  628. ;+
  629. ; setscxltmout - set up a timeout count for the SCSI for SCXLTMOUT long
  630. ;
  631. ; Returns:
  632. ;    a0.l = address of _hz_200 clock
  633. ;    d1.l = expiration time
  634. ;-
  635.  
  636. .if    DRIVER                ; to be included in driver
  637.     .extern    scxltmout
  638. .endif    ;DRIVER
  639.  
  640. setscxltmout:
  641.     movea.l    #_hz_200,a0        ; a0 -> 200 hz clock
  642.     move.l    scxltmout,d1        ; d0 = scltmout _hz_200 clicks
  643.     add.l    (a0),d1            ; d0 = curr time + # clicks to wait
  644.     rts
  645.  
  646.  
  647.  
  648. .if    !DRIVER                ; not to be included in driver
  649.  
  650. ;+
  651. ; fmtscsi() - format a SCSI unit
  652. ;
  653. ;    d0.w = physical unit number
  654. ;    d1.l = transfer length (in bytes)
  655. ;    d2.w = command length (NCMD or LCMD)
  656. ;    a0.l = buffer address
  657. ;-
  658.     .globl    _fmtscsi
  659. _fmtscsi:
  660.     andi.w    #7,d0            ; mask off the flags to get unit num
  661.     bsr    sblkscsi        ; send command block
  662.     bpl.s    .0            ; if successful, wait for status byte
  663.     rts                ; else return
  664. .0:    move.b    #3,SCSITCR        ; status in phase
  665.     move.b    SCSIREI,d0        ; clear potential interrupt
  666. .1:    btst    #5,SCSICR        ; wait forever for REQ to 
  667.     beq.s    .1            ;   come
  668.     bra    gstat            ; when REQ comes, get status byte
  669.  
  670. .endif    ;!DRIVER
  671.  
  672.